package vip.liux.front.adapter.web;

import com.github.benmanes.caffeine.cache.Cache;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import vip.liux.cache.GlobalCache;
import vip.liux.contracts.security.sms.CaptchaCache;
import vip.liux.contracts.security.sms.MapCaptchaCache;
import vip.liux.contracts.shared.kits.ProfileKit;
import vip.liux.core.exception.SystemException;

import java.security.SecureRandom;
import java.time.Duration;
import java.util.HashMap;
import java.util.Map;

/**
 * 验证码控制器
 */
@RestController
@RequestMapping("/api/captcha")
public class CaptchaController {

    // 验证码过期时间(600s)
    public static final Duration EXPIRE = Duration.ofSeconds(600);
    // 最大发送次数，默认10次
    public static final long SEND_TIMES = 10;
    // 发送限制间隔时间，默认24小时
    public static final long SAFE_TIME = 86400;
    // 缓存key
    public static final String SEND_CAPTCHA_SMS = "sendCaptchaSMS.";
    private static final Logger log = LoggerFactory.getLogger(CaptchaController.class);
    private static final SecureRandom random = new SecureRandom();
    private final Cache<String, Object> cache = GlobalCache.getCache(SEND_CAPTCHA_SMS, SAFE_TIME);
    private CaptchaCache captchaCache = new MapCaptchaCache();

    /**
     * 发送短信验证码
     *
     * @param input 手机号
     * @return 验证码
     * {
     * "key": "手机号",
     * "code": "验证码"
     * }
     */
    @PostMapping("/sms")
    public Map<String, String> sms(@RequestBody CaptchaSmsInputDto input) {
        // 缓存发送记录并判断次数
        if (!record(input.mobile())) {
            throw new SystemException("很抱歉，已超出今日最大发送次数限制");
        }
        String code = String.valueOf(random.nextInt(900000) + 100000); // 生成 100000 到 999999 之间的随机数
        captchaCache.putCodeInCache(input.mobile(), code, EXPIRE);

        Map<String, String> captcha = new HashMap<>(Map.of("key", input.mobile(), "code", code));
        // 发送短信
        if (ProfileKit.isProd()) {
            captcha.remove("code");
        }
        return captcha;
        // throw new SystemException("短信发送失败");
    }


    /**
     * 记录短信验证码发送记录并判断是否超出发送限制
     *
     * @param mobile 手机号
     * @return 是否超出发送限制
     */
    @SuppressWarnings("unchecked")
    private boolean record(String mobile) {
        Map<String, Object> record = (Map<String, Object>) cache.getIfPresent(SEND_CAPTCHA_SMS + mobile);
        if (record == null) {
            cache.put(SEND_CAPTCHA_SMS + mobile, Map.of("times", SEND_TIMES - 1));
            return true;
        }

        if ((Long) record.getOrDefault("times", 0L) <= 0L) {
            log.warn("很抱歉，已超出今日最大发送次数限制");
            return false;
        }

        cache.put(SEND_CAPTCHA_SMS + mobile, Map.of("times", (Long) record.get("times") - 1L));

        return true;
    }

    @Autowired(required = false)
    public void setCaptchaCache(CaptchaCache captchaCache) {
        this.captchaCache = captchaCache;
    }

    public record CaptchaSmsInputDto(String mobile) {
    }
}
